package indi.youxiaozhong.http;

import android.content.Context;
import android.util.Log;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.net.ssl.KeyManagerFactory;

import fi.iki.elonen.NanoHTTPD;
import indi.youxiaozhong.http.annotation.ResponseBody;

/**
 * Android 嵌入HTTP微服务
 */
public class NanoHttpServer extends NanoHTTPD {
    private final static String logTag = "NanoHttpServer";

    private NanoFileUpload uploader;

    private Map<String,String> mapping;

    private List<NanoHttpInterceptor> interceptors;

    private String rootPath = "www";

    private final Context context;

    private  boolean isHttps=true;

    public NanoHttpServer(Context context,int port,boolean isHttps){
        super(port);
        this.context = context;
        this.isHttps = isHttps;
        uploader = new NanoFileUpload(new DiskFileItemFactory());

        if (this.isHttps){
            try {
                /*InputStream keystoreStream = this.context.getAssets().open("https.bks");
                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(keystoreStream, "123456".toCharArray());
                KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                keyManagerFactory.init(keyStore, "123456".toCharArray());
                this.makeSecure(NanoHTTPD.makeSSLSocketFactory(keyStore, keyManagerFactory), null);*/

                InputStream keystoreStream = this.context.getAssets().open("https2.bks");
                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(keystoreStream, "123456".toCharArray());
                KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                keyManagerFactory.init(keyStore, "123456".toCharArray());


                this.makeSecure(NanoHTTPD.makeSSLSocketFactory(keyStore, keyManagerFactory), null);

            }catch (Exception e){
                Log.e(logTag,"加载https证书失败",e);
            }
        }


        try {
           Class<IRequestMappingData> myclass =  (Class<IRequestMappingData>) Class.forName("indi.youxiaozhong.faceid.devsetting.process.My_RequestMappingDataAutoGenerate");
           IRequestMappingData data = myclass.newInstance();
           this.mapping = data.getMapping();
           Log.i(logTag,"http映射表:"+this.mapping);
        }catch (Exception e){
            Log.e(logTag,"加载http映射数据失败:",e);
            this.mapping = new HashMap<>();
        }


        try {
            VelocityUtils.init(context);
        }catch (IOException e){
            e.printStackTrace();
        }


    }

    public void isHttps(boolean https) {
        this.isHttps = https;
    }

    public void setRootPath(String path){
        this.rootPath = path;
    }

    public void addInterceptor(NanoHttpInterceptor interceptor){
        if(this.interceptors == null){
            this.interceptors =new ArrayList<>();
        }
        this.interceptors.add(interceptor);
    }


    @Override
    public Response serve(IHTTPSession session) {
        String uri = session.getUri();
        Method method = session.getMethod();
        Log.i(logTag,String.format("URI:%s Method:%s",uri,method));

        try {
            //TODO 根据URI映射处理方法
            String action = this.mapping.get(uri);
            boolean isMultipartContent = NanoFileUpload.isMultipartContent(session);

            Map<String,List<FileItem>> files=null;
            if(isMultipartContent){
                files = uploader.parseParameterMap(session);

            }else if (Method.POST.equals(method) || Method.PUT.equals(method)) {
                session.parseBody(new HashMap<String, String>());
            }
            NanoHttpRequest request =  new NanoHttpRequest(session,context,files,rootPath);
            NanoHttpResponse response = new NanoHttpResponse(session);


            if(action!=null){
                String tmp[]=action.split("/");
                this.doRequest(tmp[0],tmp[1],request,response);
            }else{
                File file = new File(this.rootPath+uri);

                InputStream inputStream=null;
                try {
                    if(this.rootPath.startsWith("/")){
                        inputStream = new FileInputStream(rootPath+uri);
                    }else{
                        inputStream = context.getAssets().open(rootPath+uri);
                    }
                }catch (FileNotFoundException e){
                    Log.e(logTag,"404:"+uri+" not found!",e);
                }

                if(inputStream != null){
                    return newFixedLengthResponse(Response.Status.OK,getMimeTypeForFile(uri),inputStream,inputStream.available());
                }else{
                    return  newFixedLengthResponse(Response.Status.NOT_FOUND,getMimeTypeForFile(uri),"404:"+uri+" not found!");
                }


            }

            return  response.Response();
        }catch (Exception e){

            Log.e(logTag,"服务异常:"+e.getMessage(),e);
            return  newFixedLengthResponse(Response.Status.INTERNAL_ERROR,getMimeTypeForFile(uri),e.getLocalizedMessage());

        }
    }


    private void doRequest(String classsName,String funcName,NanoHttpRequest request,NanoHttpResponse response) throws Exception {


        if(this.interceptors!=null){
            for (NanoHttpInterceptor interceptor:this.interceptors ) {
                if(!interceptor.preHandle(request,response)){
                    return;
                }
            }
        }
        //ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Exception err=null;
        try {
            Class c = Class.forName(classsName);
            Object obj = c.newInstance();
            Annotation annotation = c.getAnnotation(ResponseBody.class);
            java.lang.reflect.Method method = c.getMethod(funcName, NanoHttpRequest.class, NanoHttpResponse.class);
            if (method != null) {
                Object rc = method.invoke(obj, request, response);
                if (this.interceptors != null) {
                    for (NanoHttpInterceptor interceptor : this.interceptors) {
                        interceptor.postHandle(request, response, rc);
                    }
                }
                annotation = annotation != null ? annotation : method.getAnnotation(ResponseBody.class);
                if (annotation != null) {
                    response.write(rc);
                } else if (rc instanceof String) {
                    response.write(request.getRequestDispatcher((String) rc));
                } else {
                    //request.getRequestDispatcher(String.valueOf(rc))
                    response.write(rc);
                }

            }
        }catch (Exception e){
            err=e;
        }finally {
            if (this.interceptors != null) {
                for (NanoHttpInterceptor interceptor : this.interceptors) {
                    interceptor.afterCompletion(request,response,err);
                }
            }
        }

    }
}
